package com.glebusheg.client 
{
	import com.bubbler.farm.dialog.ErrorDialog;
	import com.ek.debug.Logger;
	import com.ek.text.StringManager;
	import com.ek.utils.StringUtil;

	import mx.utils.ObjectUtil;

	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.IOErrorEvent;
	import flash.events.SecurityErrorEvent;
	import flash.net.URLLoader;
	import flash.net.URLLoaderDataFormat;
	import flash.net.URLRequest;
	import flash.net.URLRequestMethod;
	import flash.utils.ByteArray;
	import flash.utils.getTimer;
	import flash.utils.setTimeout;




	/**
	 * @author eliasku
	 */
	public class RpcCall extends EventDispatcher 
	{
		private var _type:String = RpcType.UNKNOWN;
		private var _url:String;
		private var _requestObject:Object;
		private var _responseObject:Object;
		private var _fakeResponse:ByteArray;
		
		private var _loader:URLLoader;
		private var _completeHandler:Function;
		private var _success:Boolean;
		
		private var _time0:uint;
		private var _time1:uint;
		
		public function RpcCall(type:String)
		{
			super();
			
			_type = type;

            url = ClientManager.serverURL;
		}
		
		public function sendRequest():void
		{
			_time0 = getTimer();

           sendRequestAMF();
		}

        private function sendRequestAMF():void
        {
            var urlRequest:URLRequest = new URLRequest(_url);
			var requestData:Object = {};

			requestData.call = _type;
			requestData.body = _requestObject;

			var bytes:ByteArray = new ByteArray();
			bytes.writeObject(requestData);

			Logger.message("<span class=\"log_rpc_request\">" + ObjectUtil.toString(requestData) + "</span>");

			if(!_url)
			{
				//FIXME: Специально для отладки временных интервалов.
				if(Math.random() > 0.0)
					setTimeout(onFakeComplete, 500 + Math.random() * 500);
				else
					onFakeComplete();

				return;
			}

			urlRequest.contentType = "application/x-amf";
			urlRequest.method = URLRequestMethod.POST;
			urlRequest.data = bytes;

			if(_loader)
				Logger.error("[RpcCall] Cannot send message while message is sending");

			_loader = new URLLoader();
			_loader.dataFormat = URLLoaderDataFormat.BINARY;

			addListeners();

            try
            {
                _loader.load(urlRequest);
			}
            catch (error:Error)
            {
            	Logger.error("[RpcCall] Unable to call load method: " + error.message);
            	removeListeners();
            	_loader = null;
            }
        }
		
		private function addListeners():void
		{
			_loader.addEventListener(IOErrorEvent.IO_ERROR, onLoaderError);
			_loader.addEventListener(Event.COMPLETE, onLoaderComplete);
			_loader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onLoaderError);
		}
		
		private function removeListeners():void
		{
			_loader.removeEventListener(IOErrorEvent.IO_ERROR, onLoaderError);
			_loader.removeEventListener(Event.COMPLETE, onLoaderComplete);
			_loader.removeEventListener(SecurityErrorEvent.SECURITY_ERROR, onLoaderError);
		}
		
		private function onLoaderError(e:Event):void
		{
			_time1 = getTimer();
			_success = false;
			
			var text:String = "unknown";
			
			Logger.warning("[RpcCall] (status error) Call time: " + (_time1 - _time0).toString());
			
			if(e is IOErrorEvent)
				text = (e as IOErrorEvent).text;
			else if(e is SecurityErrorEvent)
				text = (e as SecurityErrorEvent).text;
	
			Logger.warning("[RpcCall] " + text);
			
			onComplete();
			dispatchComplete();
			removeListeners();
			_loader = null;
			
			//if(ClientManager.serverURL && _type != "initialize")
				//ErrorDialog.open(StringManager.getText("connection_lost"));
		}
		
		private function onLoaderComplete(e:Event):void
		{
			_time1 = getTimer();
			_success = true;
			
			Logger.message("[RpcCall] Call time: " + (_time1 - _time0).toString());
			
			handleResponseData();
			onComplete();
			dispatchComplete();
			removeListeners();
			_loader = null;
			
			if(_responseObject)
			{
				processResponse();
			}
		}

		protected function processResponse():void
		{
			
		}

		protected function onFakeComplete():void
		{
			_time1 = getTimer();
			_success = true;
			
			Logger.message("[RpcCall] Call time: " + (_time1 - _time0).toString());
			
			handleResponseData(true);
			onComplete();
			dispatchComplete();
			
			processResponse();
		}
		
		
		protected function onComplete():void
		{

		}
		
		private function dispatchComplete():void
		{
			if(hasEventListener(Event.COMPLETE))
				dispatchEvent(new Event(Event.COMPLETE));
			
			if(_completeHandler!=null)
				_completeHandler(this);
		}
		
		private function handleResponseData(fake:Boolean = false):void
		{
			if(!fake)
			{
				if(_loader && _success)
				{
					var ba:ByteArray;
					
					if(_loader.data is ByteArray)
					{
						ba = (_loader.data as ByteArray);

						try
						{
							_responseObject = ba.readObject();
						}
						catch(e:Error)
						{
							Logger.warning("Cannot read binary structure.");
							Logger.warning(StringUtil.byteArrayString(ba));
							Logger.warning(e.message);
						}
					}
				}
			}
			else
			{
				if(_fakeResponse)
					_responseObject = _fakeResponse.readObject();
			}
			
			if(_responseObject)
				Logger.message("<span class=\"log_rpc_response\">" + ObjectUtil.toString(_responseObject) + "</span>");
		}
		
		public function get isSuccess():Boolean
		{
			return _success;
		}
		
		public function get responseObject():Object
		{
			return _responseObject;
		}
	
		public function set completeHandler(handler:Function):void
		{
			_completeHandler = handler;
		}
		
		protected function set url(value:String):void
		{
			_url = value;
		}
		
		protected function get url():String
		{
			return _url;
		}
		
		public function set requestObject(object:Object):void
		{
			_requestObject = object;
		}
		
		public function get type():String
		{
			return _type;
		}
		
		public function get fakeResponse():ByteArray
		{
			return _fakeResponse;
		}
		
		public function set fakeResponse(value:ByteArray):void
		{
			_fakeResponse = value;
		}
	}
}
